package com.ai.imagetext.service;

import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.dashscope.utils.Constants;
import io.reactivex.Flowable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;

@Service
public class DashScopeAiService {

    private static final Logger logger = LoggerFactory.getLogger(DashScopeAiService.class);

    @Value("${dashscope.api.key:sk-b00da4a48fa74d3c85445fec7d16ce39}")
    private String apiKey;

    @Value("${dashscope.model:qwen-vl-max}")
    private String model;

    /**
     * 分析图片并返回AI回复
     */
    public String analyzeImageWithAi(MultipartFile image, String prompt) throws Exception {
        try {
            logger.info("开始分析图片，文件名: {}, 大小: {} bytes",
                       image.getOriginalFilename(), image.getSize());

            // 检查图片大小（限制为4MB，避免base64过大）
            if (image.getSize() > 4 * 1024 * 1024) {
                throw new RuntimeException("图片文件过大，请上传小于4MB的图片");
            }

            // 将图片转换为base64
            String base64Image = Base64.getEncoder().encodeToString(image.getBytes());
            logger.debug("图片转换为base64完成，长度: {}", base64Image.length());

            // 构建图片URL（使用标准格式）
            String imageUrl = "data:" + image.getContentType() + ";base64," + base64Image;

            // 构建消息内容
            List<Map<String, Object>> messageContent = new ArrayList<>();
            messageContent.add(Collections.singletonMap("image", imageUrl));
            messageContent.add(Collections.singletonMap("text",
                prompt != null && !prompt.trim().isEmpty() ? prompt : "请详细描述这张图片的内容"));

            // 构建消息
            MultiModalMessage userMsg = MultiModalMessage.builder()
                    .role(Role.USER.getValue())
                    .content(messageContent)
                    .build();

            logger.debug("消息构建完成，开始调用API");

            // 调用AI服务
            return callDashScopeApi(userMsg);

        } catch (IOException e) {
            logger.error("读取图片文件失败", e);
            throw new RuntimeException("读取图片文件失败: " + e.getMessage());
        } catch (Exception e) {
            logger.error("图片分析过程中发生错误", e);
            throw e;
        }
    }

    /**
     * 纯文本对话
     */
    public String chatWithAi(String message) throws Exception {
        try {
            logger.info("开始AI文本对话，消息: {}", message);

            // 构建纯文本消息
            List<Map<String, Object>> messageContent = new ArrayList<>();
            messageContent.add(Collections.singletonMap("text", message));

            MultiModalMessage userMsg = MultiModalMessage.builder()
                    .role(Role.USER.getValue())
                    .content(messageContent)
                    .build();

            return callDashScopeApi(userMsg);

        } catch (Exception e) {
            logger.error("AI文本对话失败", e);
            throw e;
        }
    }

    /**
     * 调用DashScope API - 带重试机制
     * @author wangguiyou
     */
    private String callDashScopeApi(MultiModalMessage message) throws Exception {
        int maxRetries = 3;
        int baseDelayMs = 1000; // 基础延迟1秒
        
        for (int attempt = 1; attempt <= maxRetries; attempt++) {
            try {
                logger.info("开始调用DashScope API，模型: {}，尝试次数: {}/{}", model, attempt, maxRetries);
                logger.debug("API Key前缀: {}...", apiKey.substring(0, Math.min(10, apiKey.length())));

                MultiModalConversation conv = new MultiModalConversation();

                // 先尝试非流式调用，更简单稳定
                MultiModalConversationParam param = MultiModalConversationParam.builder()
                        .apiKey(apiKey)
                        .model(model)
                        .messages(Arrays.asList(message))
                        .incrementalOutput(false) // 先使用非流式输出
                        .build();

                logger.debug("开始同步调用API");

                // 使用同步调用
                MultiModalConversationResult result = conv.call(param);

                if (result != null) {
                    logger.debug("收到API响应: {}", result.getRequestId());

                    if (result.getOutput() != null && !result.getOutput().getChoices().isEmpty()) {
                        var choice = result.getOutput().getChoices().get(0);
                        var responseMessage = choice.getMessage();

                        if (responseMessage != null) {
                            // 尝试获取文本内容
                            List<Map<String, Object>> content = responseMessage.getContent();
                            if (content != null && !content.isEmpty()) {
                                Object text = content.get(0).get("text");
                                if (text != null) {
                                    String response = text.toString();
                                    logger.info("AI同步响应成功，内容长度: {}", response.length());
                                    return response;
                                }
                            }

                            // 如果没有content，尝试获取其他字段
                            logger.debug("响应消息结构: content={}, role={}",
                                       content != null ? content.size() : "null",
                                       responseMessage.getRole());
                        }
                    }

                    // 如果同步调用没有返回内容，尝试流式调用
                    logger.info("同步调用未返回内容，尝试流式调用");
                    return callDashScopeApiStreamWithRetry(message, attempt, maxRetries);
                }

                logger.warn("API返回null结果");
                return "AI服务暂时无法处理您的请求";

            } catch (NoApiKeyException e) {
                logger.error("API Key无效: {}", e.getMessage());
                throw new RuntimeException("API Key配置错误，请检查API Key是否正确");
            } catch (ApiException e) {
                logger.error("调用DashScope API失败，尝试次数: {}/{}, 错误: {}", attempt, maxRetries, e.getMessage());
                
                // 检查是否是可重试的错误
                if (isRetryableError(e) && attempt < maxRetries) {
                    int delayMs = baseDelayMs * attempt; // 指数退避
                    logger.info("检测到限流错误，{}毫秒后进行第{}次重试", delayMs, attempt + 1);
                    
                    try {
                        Thread.sleep(delayMs);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        throw new RuntimeException("重试被中断", ie);
                    }
                    continue; // 继续重试
                }
                
                // 不可重试的错误或已达到最大重试次数
                String errorMsg = getErrorMessage(e);
                throw new RuntimeException(errorMsg + ": " + e.getMessage());
            } catch (Exception e) {
                logger.error("调用AI服务时发生未知错误，尝试次数: {}/{}", attempt, maxRetries, e);
                
                // 对于未知错误，只在最后一次尝试时抛出异常
                if (attempt == maxRetries) {
                    throw new RuntimeException("AI服务异常: " + e.getMessage());
                }
                
                // 等待后重试
                int delayMs = baseDelayMs * attempt;
                logger.info("{}毫秒后进行第{}次重试", delayMs, attempt + 1);
                try {
                    Thread.sleep(delayMs);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("重试被中断", ie);
                }
            }
        }
        
        throw new RuntimeException("AI服务调用失败，已达到最大重试次数");
    }
    
    /**
     * 判断是否为可重试的错误
     * @author wangguiyou
     */
    private boolean isRetryableError(ApiException e) {
        String message = e.getMessage();
        return message != null && (
            message.contains("ServiceUnavailable") ||
            message.contains("Throttling") ||
            message.contains("Too many requests") ||
            message.contains("throttled") ||
            message.contains("capacity limits")
        );
    }

    /**
     * 流式调用DashScope API - 带重试机制
     * @author wangguiyou
     */
    private String callDashScopeApiStreamWithRetry(MultiModalMessage message, int currentAttempt, int maxRetries) throws Exception {
        try {
            return callDashScopeApiStream(message);
        } catch (Exception e) {
            if (currentAttempt < maxRetries && isRetryableException(e)) {
                int delayMs = 1000 * currentAttempt;
                logger.info("流式调用失败，{}毫秒后重试，当前尝试: {}/{}", delayMs, currentAttempt, maxRetries);
                Thread.sleep(delayMs);
                return callDashScopeApiStream(message);
            }
            throw e;
        }
    }
    
    /**
     * 判断是否为可重试的异常
     * @author wangguiyou
     */
    private boolean isRetryableException(Exception e) {
        String message = e.getMessage();
        return message != null && (
            message.contains("ServiceUnavailable") ||
            message.contains("Throttling") ||
            message.contains("Too many requests") ||
            message.contains("throttled") ||
            message.contains("capacity limits")
        );
    }
    
    /**
     * 流式调用DashScope API
     * @author wangguiyou
     */
    private String callDashScopeApiStream(MultiModalMessage message) throws Exception {
        try {
            logger.info("开始流式调用DashScope API");

            MultiModalConversation conv = new MultiModalConversation();

            MultiModalConversationParam param = MultiModalConversationParam.builder()
                    .apiKey(apiKey)
                    .model(model)
                    .messages(Arrays.asList(message))
                    .incrementalOutput(true)
                    .build();

            StringBuilder reasoningContent = new StringBuilder();
            StringBuilder finalContent = new StringBuilder();

            Flowable<MultiModalConversationResult> result = conv.streamCall(param);

            result.blockingForEach(response -> {
                handleGenerationResult(response, reasoningContent, finalContent);
            });

            // 返回完整内容
            String fullResponse = finalContent.toString();
            if (fullResponse.isEmpty() && reasoningContent.length() > 0) {
                fullResponse = reasoningContent.toString();
            }

            if (!fullResponse.isEmpty()) {
                logger.info("AI流式响应成功，内容长度: {}", fullResponse.length());
                return fullResponse;
            } else {
                logger.warn("流式调用也未返回内容");
                return "AI服务暂时无法处理您的请求";
            }

        } catch (Exception e) {
            logger.error("流式调用失败", e);
            throw e;
        }
    }

    /**
     * 获取错误信息
     * @author wangguiyou
     */
    private String getErrorMessage(ApiException e) {
        String errorMsg = "AI服务调用失败";
        String message = e.getMessage();

        if (message.contains("InvalidParameter")) {
            errorMsg = "请求参数无效，请检查图片格式或提示词";
        } else if (message.contains("Throttling") || message.contains("Too many requests") || 
                   message.contains("throttled") || message.contains("ServiceUnavailable")) {
            errorMsg = "服务繁忙，系统已自动重试，请稍后再试";
        } else if (message.contains("capacity limits")) {
            errorMsg = "系统容量限制，已自动重试，请稍后再试";
        } else if (message.contains("InsufficientBalance")) {
            errorMsg = "账户余额不足";
        } else if (message.contains("ModelNotFound") || message.contains("model not found")) {
            errorMsg = "模型不存在，当前模型: " + model;
        } else if (message.contains("Unauthorized")) {
            errorMsg = "API Key无效或权限不足";
        } else if (message.contains("InvalidApiKey")) {
            errorMsg = "API Key格式错误";
        }

        return errorMsg;
    }

    /**
     * 处理生成结果 - 根据官方示例实现
     */
    private void handleGenerationResult(MultiModalConversationResult message,
                                      StringBuilder reasoningContent,
                                      StringBuilder finalContent) {
        try {
            if (message.getOutput() == null || message.getOutput().getChoices().isEmpty()) {
                return;
            }

            var choice = message.getOutput().getChoices().get(0);
            var responseMessage = choice.getMessage();

            if (responseMessage == null) {
                return;
            }

            // 获取推理内容
            String reasoning = responseMessage.getReasoningContent();
            if (reasoning != null && !reasoning.isEmpty()) {
                reasoningContent.append(reasoning);
                logger.debug("收到推理内容: {}", reasoning.length() > 100 ?
                    reasoning.substring(0, 100) + "..." : reasoning);
            }

            // 获取最终内容
            List<Map<String, Object>> content = responseMessage.getContent();
            if (content != null && !content.isEmpty()) {
                Object text = content.get(0).get("text");
                if (text != null) {
                    String textContent = text.toString();
                    finalContent.append(textContent);
                    logger.debug("收到文本内容: {}", textContent.length() > 100 ?
                        textContent.substring(0, 100) + "..." : textContent);
                }
            }

        } catch (Exception e) {
            logger.warn("处理生成结果时出错", e);
        }
    }

    /**
     * 流式调用（用于实时响应）
     */
    public CompletableFuture<String> streamAnalyzeImage(MultipartFile image, String prompt) {
        CompletableFuture<String> future = new CompletableFuture<>();

        try {
            String base64Image = Base64.getEncoder().encodeToString(image.getBytes());
            String imageUrl = "data:" + image.getContentType() + ";base64," + base64Image;

            MultiModalMessage userMsg = MultiModalMessage.builder()
                    .role(Role.USER.getValue())
                    .content(Arrays.asList(
                            Collections.singletonMap("image", imageUrl),
                            Collections.singletonMap("text", prompt != null ? prompt : "请详细描述这张图片的内容")
                    ))
                    .build();

            MultiModalConversation conv = new MultiModalConversation();
            MultiModalConversationParam param = MultiModalConversationParam.builder()
                    .apiKey(apiKey)
                    .model(model)
                    .messages(Arrays.asList(userMsg))
                    .incrementalOutput(true)
                    .build();

            StringBuilder fullResponse = new StringBuilder();

            Flowable<MultiModalConversationResult> result = conv.streamCall(param);
            result.blockingForEach(message -> {
                if (message.getOutput() != null && !message.getOutput().getChoices().isEmpty()) {
                    List<Map<String, Object>> content = message.getOutput()
                            .getChoices().get(0).getMessage().getContent();

                    if (content != null && !content.isEmpty()) {
                        Object text = content.get(0).get("text");
                        if (text != null) {
                            fullResponse.append(text.toString());
                        }
                    }
                }
            });

            future.complete(fullResponse.toString());

        } catch (Exception e) {
            logger.error("流式调用失败", e);
            future.completeExceptionally(e);
        }

        return future;
    }
}
